#ifndef VL_WEAK_PTR
#define VL_WEAK_PTR

#include <cassert>
#include <algorithm>
#include "shared_ptr.hpp"

namespace vl
{

struct weak_ptr_common
{
	weak_ptr_common()
	: v(0)
	{
	}
	
	weak_ptr_common(shared* v_init)
	{
		_set(v_init);
	}
	
	weak_ptr_common(weak_ptr_common const& b)
	{
		_set(b.v);
	}
		
	~weak_ptr_common()
	{
		_release();
	}
		
	void reset(shared* v)
	{
		_release();
		_set(v);
	}
	
	void _release()
	{
		if(v)
		{
			weak_ptr_common* last = 0;
			for(weak_ptr_common* p = v->_first; p;)
			{
				if(p == this)
				{
					if(last)
						last->next = p->next;
					else
						v->_first = p->next;
					return;
				}
				
				last = p;
				p = last->next;
			}
		}
	}
	
	void _set(shared* v_new)
	{
		v = v_new;
		next = v->_first;
		v->_first = this;
	}
	
	weak_ptr_common* next;
	shared* v;
};

template<typename T>
struct weak_ptr : weak_ptr_common
{
	weak_ptr()
	{
	}
	
	weak_ptr(weak_ptr const& v)
	: weak_ptr_common(v)
	{
	}
	
	weak_ptr(shared_ptr<T> const& b)
	: weak_ptr_common(b)
	{
	}
	
	weak_ptr(deferred_ptr<T> const& b)
	: weak_ptr_common(b.v)
	{
	}
	
	weak_ptr& operator=(weak_ptr const& b)
	{
		weak_ptr_common::reset(b.v);
		return *this;
	}
	
	weak_ptr& operator=(shared_ptr<T> const& b)
	{
		weak_ptr_common::reset(b.v);
		return *this;
	}
	
	shared_ptr<T> lock()
	{
		return static_cast<T*>(v);
	}
		
	void swap(weak_ptr& b)
	{
		std::swap(v, b.v);
	}
};

}

#endif //VL_WEAK_PTR
